#pragma once
#include <memory>
#include <string>
#include <jsoncpp/json/json.h>

//#define SELF 1 // SELF：表示使用自定义序列化
// json串自带换行
namespace protocol_ns
{
    /*报文=报头+有效载荷
    报头是有效载荷的长度
    约定发送到网络中的数据格式：len"\r\n"{x op y} 这是一个完整的请求。
    {}为序列化后的json串，通过json串保证通信双发以统一的格式接收、发送数据，防止发送和读取时可能引起的因数据类型不匹配导致的数据丢失问题
    除了需要序列化，还要将序列化后的json串进行编码为指定格式，这是为了保证在网络接收数据时能够判断接受的是否为一个完整的request。

    自定义序列化后的格式:_x _op _y，分隔符用空格连接
    */
    // 约定协议：报文长度+\r\n+报文内容+\r\n
    std::string SEP = "\r\n";
    char PROTSEP = ' ';
    class Request
    {
    public:
        Request()
        {
        }
        Request(int x, int y, char op)
            : _x(x), _y(y), _op(op)
        {
        }

        // out为序列化后的字符串
        bool Serialize(std::string *out)
        {
#ifdef SELF
            // requeset序列化后:_x _op _y
            std::string x_data_str = std::to_string(_x);
            std::string y_data_str = std::to_string(_y);
            *out = x_data_str + PROTSEP + _op + PROTSEP + y_data_str;
            return true;

#else
            Json::Value root;
            Json::FastWriter writer;
            root["x"] = _x;
            root["y"] = _y;
            root["op"] = _op;
            *out = writer.write(root);
            return true;
#endif
        }

        // 将in序列化
        bool Deserialize(const std::string &in)
        {
#ifdef SELF
            // in一定是_x _op _y的形式
            size_t left_pos = in.find(PROTSEP);
            size_t ritght_pos = in.rfind(PROTSEP);
            // 说明in的形式不对
            if (left_pos == std::string::npos || ritght_pos == std::string::npos) return false;

            std::string x_data_str = in.substr(0, left_pos);
            std::string y_data_str = in.substr(ritght_pos + sizeof(PROTSEP));
            _x = std::stoi(x_data_str);
            _x = std::stoi(y_data_str);
            return true;
#else
            Json::Reader reader;
            Json::Value root;
            bool ret = reader.parse(in, root);
            if (!ret)
                return false;

            _x = root["x"].asInt();
            _y = root["y"].asInt();
            _op = root["op"].asInt(); // char本质也是int
            return true;
#endif
        }

    public:
        int _x;
        int _y;
        char _op;
    };

    class Response
    {
    public:
        Response(int res = 0, int code = 0) : _res(res), _code(code) {}
        // out为序列化后的字符串
        bool Serialize(std::string *out)
        {
#ifdef SELF

            // response序列化后:_res _code
            std::string res_str = std::to_string(_res);
            std::string code_str = std::to_string(_code);
            *out = res_str + PROTSEP + code_str;
            return true;
#else
            Json::Value root;
            Json::FastWriter writer;
            root["result"] = _res;
            root["code"] = _code;
            *out = writer.write(root);
            return true;
#endif
        }

        // 将in反序列化
        bool Deserialize(const std::string &in)
        {
#ifdef SELF
             // in一定是_res _code的形式
            size_t pos = in.find(PROTSEP);
           
            // 说明in的形式不对
            if (pos == std::string::npos) return false;

            std::string res_str = in.substr(0, pos);
            std::string code_str = in.substr(pos + sizeof(PROTSEP));
            _res = std::stoi(res_str);
            _code = std::stoi(code_str);
            return true;

#else
            Json::Reader reader;
            Json::Value root;
            bool ret = reader.parse(in, root);
            if (!ret)
                return false;

            _res = root["result"].asInt();
            _code = root["code"].asInt();
            return true;
#endif
        }

    public:
        int _res;  // 运算结果
        int _code; // 运算码    约定---0:success 1:除零错误 2:模0错误 3:非法运算
    };

    class Factory
    {
    public:
        Factory(std::string op = "+-*/%^&")
            : _op(op)
        {
            srand(time(nullptr) ^ getpid());
        }
        std::shared_ptr<Request> BulidRequest()
        {
            int x = rand() % 10;
            int y = rand() % 5;
            char op = _op[rand() % _op.size()];
            return std::make_shared<Request>(x, y, op);
        }
        std::shared_ptr<Response> BulidResponse()
        {
            return std::make_shared<Response>();
        }

    private:
        std::string _op;
    };
    // 将序列化后的json串加工为完整的请求
    std::string Encode(const std::string &json_string)
    {
        int json_str_len = json_string.length();
        // 协议化json串
        std::string proto_str = std::to_string(json_str_len);
        proto_str += SEP;
        proto_str += json_string;
        proto_str += SEP;

        return proto_str;
    }

    // 将读取的字符串转成json串
    /*
    inbuffer可能的情况:
    len
    len"\r\n"{
    len"\r\n"{     }
    len"\r\n"{     }"\r\n"
    len"\r\n"{     }"\r\n"len"\r\n"
    len"\r\n"{     }"\r\n"len"\r\n"{     }
    len"\r\n"{     }"\r\n"len"\r\n"{     }"\r\n"len"\r\n"{     }"\r\n"
    */
    std::string Decode(std::string &inbuffer)
    {
        auto pos = inbuffer.find(SEP);
        // 情况一:返回空串
        if (pos == std::string::npos)
            return std::string();

        // 得到一个完整请求的长度
        std::string package_len_str = inbuffer.substr(0, pos);
        int package_len = std::stoi(package_len_str);
        int total_len = package_len_str.length() + package_len + 2 * SEP.length();

        // inbuffer不包含完整的报文
        if (inbuffer.length() < total_len)
            return std::string();

        // 从inbuffer中提取一个json串，同时删除这个完整的报文
        std::string json_str = inbuffer.substr(pos + SEP.size(), package_len);
        inbuffer.erase(0, total_len);

        return json_str;
    }
}